//
//  PPGHRM.h
//  PPG_Signals_Analysis
//
//  Created by 饶旋 on 19/11/15.
//  Copyright © 2019年 饶旋. All rights reserved.
//

#ifndef PPGHRM_h
#define PPGHRM_h

// #define ENABLE_PPG_HRV_DETECT

#define PPG_SIZE 68000 // 27700 // 4通道-27700(bytes), 3通道-26700(bytes), 2通道-25500(bytes), 1通道-24700(bytes)
#define HRV_SIZE 2500  // byte

/**

 ppg_param_t参数设置说明:

 1. 心率模式设置: 跑步类运动, 包括户外跑, 室内跑, 越野跑, 登山, 徒步等都设置sport_type为跑步(1), 其中间歇模式设置sport_type为间歇跑(2),
                骑行, 水上运动, 滑雪, 健身, 有氧运动等设置sport_type为骑行模式(3),
                游泳设置sport_type为游泳模式(4),
                日常, 睡眠心率设置sport_type为日常模式(5)

 2. 体能参数设置: 体能参数会在sport_type设置为跑步(1)或间歇跑(2)时生效,
                建议只在模型运动时输入体能参数(户外跑和操场跑), 其他运动mdl_type设置为(0)

 3. [min_init_hr, max_init_hr]提供了第一个心率的出值区间, 除睡眠时设置min_init_hr(40), max_init_hr(96)
    其他模式均可设置为min_init_hr(50), max_init_hr(96)

 4. 日常心率开关逻辑: 一旦心率trust_level==3时，可关闭心率, 并记录当前返回的心率值(无需取平均),
                   若无trust_level==3的心率值, 可取所有心率的平均, 也可按trust_level取加权平均

 5. log收集逻辑: 正式版本打开数据采集开关或在debug版本中同时记录COROS_HR和PIXART_HR, 否则可不跑PIXART算法

 */

// 心率算法参数设置
typedef struct
{
    unsigned char sport_type;        // 运动类型，PI测试-0, 跑步-1, 间歇跑-2, 骑行-3(健身, 有氧运动等使用骑行模式),
                                     // 游泳-4, 日常、睡眠-5
    unsigned char ppg_fs;            // ppg采样频率, 赫兹, eg: pixart_fs = 20Hz
    unsigned char ppg_chn;           // ppg通道数
    unsigned char rest_hr;           // 静息心率
    unsigned char max_hr;            // 最大心率
    unsigned char init_hr;           // 初始化心率值, 0-无有效初始化心率, 非0-直接以当前心率开始心率检测
    unsigned char min_init_hr;       // 第一个心率的最小值, 睡眠可设置40, 其他设置60
    unsigned char max_init_hr;       // 第一个心率的最大值, 可设置96
    unsigned char mdl_type;          // 1.0体能模型生效标志位(心率预测模型)
    unsigned char ompd_type;         // 2.0体能模型生效标志位(能力评估模型)
    unsigned char enable_auto_sport; // 自动运动模式切换开关,
                                     // 0-手表初始化置0, 主要参考开启的运动类型
                                     // 1-心率臂带初始化置1, 主要依赖自动运动模式检测
    unsigned char enable_netwrok;    // 0-使用信号处理方法进行去噪, 1-使用卷积记忆网络去噪
    float mdl_k;                     // 全距离段体能模型的k值
    float mdl_b;                     // 全距离段体能模型的b值
    float vo2max_pace;               // 最大摄氧量配速, 体能模型处获取, 单位m/s
} ppg_param_t;

typedef struct
{
    int time;       // 采样间隔, 单位毫秒
    int *green_buf; // 每秒新增的绿光ppg数据，时间从小到大排列，多通道数据为一组，如2通道数据
                    // {green0_chn1, green0_chn2, green1_chn1, green1_chn2...}, 2通道20Hz
                    // 采样即每秒包含20*2=40个数据
    int green_num;  // 新增绿光采样个数，如20Hz采样时, 该值为20
    int *red_buf;   // 每秒新增红光ppg数据, 格式和绿光一样, 通道数与绿光共享, 不需要红光数据给NULL
    int red_num;    // 新增红光采样个数, 不需要红光数据给0
    int *ir_buf;    // 每秒新增红外ppg数据, 格式和绿光一样, 通道数与绿光共享, 不需要红外数据给NULL
    int ir_num;     // 新增红外采样个数, 不需要红外数据给0
    int ppg_chn;    // ppg通道数
    short *acc;     // 每秒新增acc数据，时间从小到大，按x, y, z顺序排列，参考ppg排列方式
    int acc_num;    // 新增acc数据组数，由于以ppg采样为准，可能为24，25，26...尽量保证和ppg数据对齐
    int cad;        // 步频大小，从计步算法处刷新获取
    int touch;      // 接触标志，0-未接触 1-接触
    int waiting;    // 在搜星或暂停界面，该值为1，运动中为0
    float pace_ms;  // 实时配速, m/s
    int slope;      // 坡度, 单位百分比(由气压算法获取)
    float psensor;  // 电容传感器读数
    void (*cb)(void); // 回调函数, 用于拆分推理过程, 给固件控制运算优先级
} ppg_input_data_t;

typedef struct
{
    unsigned char unstable_wearing; // 1-松佩戴, 可以进行提示, 只会上报1次, 获取到后即清0, 0-佩戴正常
    unsigned char hr;               // 心率, bpm
    unsigned char hr_fitness;       // 体能模型预测心率, 存储非0值, bpm
    unsigned char trust_level;      // 心率置信度, 取值范围0-3, 越大置信度越高
    float pi;                       // PI值，未检测到有效值时返回0
} ppg_output_data_t;

//**************************************************************************
// @brief：心率算法初始化
//
// @param[in]   pData: 待分配内存
// @param[in]   para: 见'ppghrm_param_t'结构体数据说明
// @param[out]  函数返回实际占用内存大小，单位byte
//
//**************************************************************************
int PPGHRM_Init(char *pData, ppg_param_t para);

//**************************************************************************
// @brief：获取心率算法结果
//
// @param[out]  ppg_res: 见'ppg_output_data_t'说明
// @param[out]  函数返回错误码, 0正常，否则存在异常
//
//**************************************************************************
int PPGHRM_GetResult(ppg_output_data_t *ppg_res);

//**************************************************************************
// @brief：心率算法sensor数据更新，每秒调用（以ppg采样数为准，20Hz采样即采集到20组ppg数据调用一次）
//
// @param[in]   ppg_input: 见'ppg_input_data_t'说明
// @param[out]  函数返回错误码, 0正常，否则存在异常
//
//**************************************************************************
int PPGHRM_UpdateSensor(const ppg_input_data_t *ppg_input);

#if defined(ENABLE_PPG_HRV_DETECT)

/**
 HRV Part, ppg信号只支持100Hz采样
 */

//**************************************************************************
// @brief：获取当前时刻所有心率的平均值及有效rr个数
//
// @param[out]  hr: 平均心率
// @param[out]  rr_num: 参与hrv计算的有效rr个数
//
//**************************************************************************
int PPGHRV_GetMeanHR(int *hr, int *rr_num);

//**************************************************************************
// @brief：获取当前时刻所有心跳数据计算得到的HRV
//
// @param[out]  yf_hrv: yf自研hrv算法结果, 未达到出值标准返回0
// @param[out]  pix_hrv: 利用pixart的rri, 过滤异常值后，生成的hrv结果, 未达到出值标准返回0
//
//**************************************************************************
int PPGHRV_GetRealTimeHRV(int *yf_hrv, int *pix_hrv);

//**************************************************************************
// @brief：获取HRV值
//
// @param[in]   out_len: 生成hrv的rri窗口长度，最大支持300, 默认可设置30s
// @param[out]  yf_hrv: yf自研hrv算法结果, 未达到出值标准返回0
// @param[out]  pix_hrv: 利用pixart的rri, 过滤异常值后，生成的hrv结果, 未达到出值标准返回0
//
//**************************************************************************
int PPGHRV_GetHRV(int out_len, int *yf_hrv, int *pix_hrv);

//**************************************************************************
// @brief：获取rri
//
// @param[out]  函数返回yf算法生成的rri, 单位ms
//
//**************************************************************************
int PPGHRV_GetRRI(void);

//**************************************************************************
// @brief：hrv算法初始化
//
// @param[in]   pData: 待分配内存
// @param[out]  函数返回实际占用内存大小，单位byte
//
//**************************************************************************
int PPGHRV_Init(char *pData);

//**************************************************************************
// @brief：hrv算法sensor数据更新, 建议每200ms调用一次,
//
// @param[in]   ppg: 每秒新增的ppg数据，时间从小到大排列，多通道数据为一组，如2通道数据
//                   {ppg0_chn1, ppg0_chn2, ppg1_chn1, ppg1_chn2...}, 2通道20Hz
//                   采样即每秒包含20*2=40个数据
// @param[in]   ppg_chn: 通道数量
// @param[in]   ppg_num: 新增ppg采样个数，20HZ采样时为20
// @param[in]   touch: 接触标志，0-未接触 1-接触
// @param[in]   rri: pixart rri数据, 未获取到结果输入0, 以RRI_LOG为例, 每秒只可输入一次有效值, 其余时间输入0
// @param[out]  函数返回错误码, 0正常，否则存在异常
//
//**************************************************************************
int PPGHRV_Update(const int *ppg, int ppg_chn, int ppg_num, int touch, int rri);

#endif

// 心率算法版本号
extern const char *PPGHRM_Version;

#endif /* PPGHRM_h */
